﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.ServiceModel;
using SecurityFoundation;
using SecurityFoundation.Entities;


namespace SecurityAgent
{
    [SecurityExceptionHandler(AttributePriority=99)]
    public class ProfileProviderService : IProfileProviderService
    {

        //protected bool IsAuthorized(string applicationKey, string userToken)
        //{
        //    // Profile service is an application service, so it will check against the admin role of the current application.  Role service on the other hand is checking the realm admin role.
        //    //string userToken = OperationContext.Current.IncomingMessageHeaders.GetHeader<string>("UserToken", "ns");
        //    if (String.IsNullOrEmpty(userToken)) return false;

        //    RoleProviderService roleService = new RoleProviderService();

        //    return roleService.IsUserInRole(applicationKey, userToken, string.Empty, Constant.ADMIN_ROLE);
        //}
        
        
        #region IProfileProviderService Members

        [RequireAdminAccess(AttributePriority = 10)]
        public int DeleteInactiveProfiles(string applicationKey, string operatorToken, DateTime userInactiveSinceDate)
        {
            throw new FaultException<NotImplementedException>(new NotImplementedException());
        }

        [RequireAdminAccess(AttributePriority = 10)]
        public int DeleteProfilesByUsername(string applicationKey, string operatorToken, string[] usernames)
        {
            throw new FaultException<NotImplementedException>(new NotImplementedException());
        }

        [RequireAdminAccess(AttributePriority = 10)]
        public List<ProfileInfo> FindInactiveProfilesByUserName(string applicationKey, string operatorToken, string usernameToMatch, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new FaultException<NotImplementedException>(new NotImplementedException());
        }

        [RequireAdminOrSelfAccess(AttributePriority = 10)]
        public List<ProfileInfo> FindProfilesByUserName(string applicationKey, string operatorToken, string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new FaultException<NotImplementedException>(new NotImplementedException());
        }

        [RequireAdminAccess(AttributePriority = 10)]
        public List<ProfileInfo> GetAllInactiveProfiles(string applicationKey, string operatorToken, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new FaultException<NotImplementedException>(new NotImplementedException());
        }

        [RequireAdminAccess(AttributePriority = 10)]
        public List<ProfileInfo> GetAllProfiles(string applicationKey, string operatorToken, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new FaultException<NotImplementedException>(new NotImplementedException());
        }

        [RequireAdminAccess(AttributePriority = 10)]
        public int GetNumberOfInactiveProfiles(string applicationKey, string operatorToken, DateTime userInactiveSinceDate)
        {
            throw new FaultException<NotImplementedException>( new NotImplementedException());
        }

        [RequireAdminOrSelfAccess(AttributePriority = 10)]
        public ProfilePropertyValueCollection GetPropertyValues(string applicationKey, string userToken, string UserName, string[] PropertyNames)
        {
            string user = string.Empty;

            if( String.IsNullOrEmpty(UserName))
            {
                SecurityToken token = Repository.GetToken(new Guid(userToken));
            
                if( token != null )
                     user = token.UserName;
            }
            else
                user = UserName;

            if( String.IsNullOrEmpty(user))
            {
                throw new FaultException("No User Specified for profile property");
            }   

            UserProfileData profile = Repository.GetUserProfileData(new Guid(applicationKey), user);

            if( profile == null ) return null;

            try
            {
                XDocument xdoc = XDocument.Parse( profile.ProfileData );

                ProfilePropertyValueCollection ret = new ProfilePropertyValueCollection();

                foreach( string propertyName in PropertyNames )
                {
                    var query = ( from en in xdoc.Root.Elements(propertyName)
                                select en ).FirstOrDefault();

                    if( query != null )
                    {
                        ret.Add(new ProfilePropertyValue { PropertyName = propertyName, PropertyValue = query.Value});
                    }
                }

                return ret;
            }
            catch(Exception ee )
            {
                throw new FaultException( ee.Message);
            }
        }

        [RequireAdminOrSelfAccess(AttributePriority = 10)]
        public bool SetPropertyValues(string applicationKey, string userToken, string UserName, ProfilePropertyValue[] values)
        {
            //SecurityToken token = Repository.GetToken(new Guid(userToken));
            
            //if( token == null )
            //     throw new FaultException<UnauthorizedAccessFault>(new UnauthorizedAccessFault{ Application = applicationKey, Object="Properties", Operation="SetPropetyValues"});

            //string user;


            ///// if user name is provided and doesn't match the user name for the token, then the userToken must belong to an admin user.  The services can pass the userToken they received to get the role information of the user.
            //if( !String.IsNullOrEmpty(UserName) && UserName != token.UserName )
            //{
            //   // if (!IsAuthorized(applicationKey, userToken))
            //   //     throw new FaultException<UnauthorizedAccessFault>(new UnauthorizedAccessFault{ Application = applicationKey, Object="Roles", Operation="SetPropertyValueForOtherUser"});
                 
            //    user = UserName;
            //}
            //else
            //    user = token.UserName;

            string user = string.Empty;

            if( String.IsNullOrEmpty(UserName))
            {
                SecurityToken token = Repository.GetToken(new Guid(userToken));
            
                if( token != null )
                     user = token.UserName;
            }
            else
                user = UserName;

            if( String.IsNullOrEmpty(user))
            {
                throw new FaultException("No User Specified for profile property");
            }   

            UserProfileData profile = Repository.GetUserProfileData(new Guid(applicationKey), user);

            if( profile == null ) 
            {
                profile = new UserProfileData();
                profile.ProfileDataId = 0;
                profile.UserName = user;
                profile.ApplicationKey = new Guid(applicationKey);
                profile.LastUpdated = DateTime.Now;
            }

            try
            {
                XDocument xdoc;
                
                if( String.IsNullOrEmpty(profile.ProfileData ))
                {
                    xdoc = new XDocument
                        (
                            new XDeclaration("1.0", "utf-8", null)
                            , new XElement( "Profile", 
                                new XElement("UserName", user),
                                new XElement("ApplicationKey", applicationKey)
                                )
                        );
                }
                else
                {
                    xdoc = XDocument.Parse( profile.ProfileData);
                }

                foreach( ProfilePropertyValue property in values )
                {
                    var query = ( from en in xdoc.Root.Elements(property.PropertyName)
                                select en ).FirstOrDefault();

                    if( query != null )
                    {
                        query.Value = property.PropertyValue;
                    }
                    else
                    {
                        xdoc.Root.Add( new XElement(property.PropertyName, property.PropertyValue));
                    }
                }

                profile.ProfileData = xdoc.ToString();
                
            }
            catch(Exception ee )
            {
                throw new FaultException( ee.Message);
            }

            if( profile.ProfileDataId == 0 )
            {
                Repository.InsertProfileData(profile);
            }
            else
            {
                Repository.UpdateProfileData(profile);
            }

            return true;
        }

        #endregion
    }
}
